/*
Copyright (C) 2021-2025 Casa Xu (also Zhiyan Xu) from HIT

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*
 * LOS_W25Q64.c
 *
 *  Created on: 2022年6月23日
 *      Author: 64435
 */

#include "LOS_W25Q64.h"


void LOS_W25Q64_ReadID(uint8_t* ID)
{
    uint16_t rbuf;
    uint8_t rbuf_8bit[2];
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_JEDEC_ID, CS_W25Q64);
    rbuf = LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, 0XFF, CS_W25Q64);
    memcpy(rbuf_8bit, &rbuf, 2);
    ID[0] = rbuf_8bit[1];
    rbuf = LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, 0XFF, CS_W25Q64);
    memcpy(rbuf_8bit, &rbuf, 2);
    ID[1] = rbuf_8bit[1];
    rbuf = LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, 0XFF, CS_W25Q64);
    memcpy(rbuf_8bit, &rbuf, 2);
    ID[2] = rbuf_8bit[1];
}

void LOS_W25Q64_WriteEnable()
{
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_Write_Enable, CS_W25Q64);
}

void LOS_W25Q64_WriteDisable()
{
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_Write_Disable, CS_W25Q64);
}

uint32_t LOS_W25Q64_WaitForBusyStatus()
{
    uint32_t Timeout = 0xFFFFF;
    uint16_t rbuf;
    uint8_t rbuf_8bit[2];
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Read_Status_register_1, CS_W25Q64);   
    while (Timeout > 0)
    {
        rbuf = LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64);
        memcpy(rbuf_8bit, &rbuf, 2);
        if ((rbuf_8bit[1] & 0x01) == 0)// 检查忙状态是否结束
        {
            LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64);
            break;
        }    
        Timeout--;
        if (Timeout == 0)
        {
            break;
        }
    }
    return Timeout;    
}

void LOS_W25Q64_SectorErase(uint32_t Sector_Address)
{
    static uint8_t bytebuf = 0;
    static uint32_t rt = 0;
	LOS_W25Q64_WriteEnable();//W25Q64写使能	
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Sector_Erase_4KB, CS_W25Q64);
    bytebuf = Sector_Address >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = Sector_Address >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = Sector_Address;
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
	rt = LOS_W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64_WriteDisable();//W25Q64禁止写使能
}


void LOS_W25Q64_BlockErase(uint32_t Block_Address)
{
    uint8_t bytebuf = 0;
    LOS_W25Q64_WriteEnable();//W25Q64写使能	 
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Block_Erase_64KB, CS_W25Q64);
    bytebuf = (Block_Address & 0xFF0000) >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = (Block_Address & 0xFF00) >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = Block_Address & 0xFF;
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    LOS_W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64_WriteDisable();//W25Q64禁止写使能
}

void LOS_W25Q64_ChipErase()
{
    LOS_W25Q64_WriteEnable();//W25Q64写使能	 
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_Chip_Erase, CS_W25Q64);
    LOS_W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64_WriteDisable();//W25Q64禁止写使能
}

void LOS_W25Q64_PageWrite(uint32_t address, uint8_t *data, uint16_t dataSize)
{
    static uint8_t bytebuf;
    uint16_t i  = 0;
    uint16_t chunkSize = 0;
    LOS_W25Q64_WriteEnable();//W25Q64写使能    
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Page_Program, CS_W25Q64);
    bytebuf = (address & 0xFF0000) >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = (address & 0xFF00) >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = address & 0xFF;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);  
    if (dataSize <= 256)
    {
        for (i = 0; i < (dataSize - 1); i++)
        {
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, data[i], CS_W25Q64);
        }
        LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, data[i], CS_W25Q64);
    }
    else
    {
        for (i = 0; i < 255; i++)
        {
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, data[i], CS_W25Q64);
        }
        LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, data[i], CS_W25Q64);
        dataSize -= 256;
        data += 256;        
        // 写入剩余数据
        LOS_W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
        address += 256;        
        while (dataSize > 0)
        {
            LOS_W25Q64_WriteEnable();//W25Q64写使能
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Page_Program, CS_W25Q64); 
            bytebuf = (address & 0xFF0000) >> 16;
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
            bytebuf = (address & 0x00FF00) >> 8;
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
            bytebuf = address & 0xFF;
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
            chunkSize = (dataSize > 256) ? 256 : dataSize;
            for (i = 0; i < chunkSize - 1; i++)
            {
                LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, data[i], CS_W25Q64);
            }
            LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, data[i], CS_W25Q64);       
            LOS_W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	         
            dataSize -= chunkSize;
            data += chunkSize;
            address += chunkSize;
        }
    }    
    LOS_W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64_WriteDisable();//W25Q64禁止写使能
}


void LOS_W25Q64_ReadData(uint32_t address, uint8_t *data, uint16_t dataSize)
{
	uint16_t i;
    uint8_t bytebuf;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Read_Data, CS_W25Q64);
    bytebuf = (address & 0xFF0000) >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = (address & 0xFF00) >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    bytebuf = address & 0xFF;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64);
    for (i = 0; i < dataSize - 1; i++)
    {
        data[i] = LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64);
    }    
    data[i] = LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64);
}


void LOS_W25Q64S_WriteEnable()
{
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_Write_Enable, CS_W25Q64_S);
}

void LOS_W25Q64S_WriteDisable()
{
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_Write_Disable, CS_W25Q64_S);
}

uint32_t LOS_W25Q64S_WaitForBusyStatus()
{
    uint32_t Timeout = 0xFFFFF;
    uint16_t rbuf;
    uint8_t rbuf_8bit[2];
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Read_Status_register_1, CS_W25Q64_S);   
    while (Timeout > 0)
    {
        rbuf = LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64_S);
        memcpy(rbuf_8bit, &rbuf, 2);
        if ((rbuf_8bit[1] & 0x01) == 0)// 检查忙状态是否结束
        {
            LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64_S);
            break;
        }    
        Timeout--;
        if (Timeout == 0)
        {
            break;
        }
    }
    return Timeout;    
}

void LOS_W25Q64S_SectorErase(uint32_t Sector_Address)
{
    static uint8_t bytebuf = 0;
    static uint32_t rt = 0;
	LOS_W25Q64S_WriteEnable();//W25Q64写使能	
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Sector_Erase_4KB, CS_W25Q64_S);
    bytebuf = Sector_Address >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = Sector_Address >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = Sector_Address;
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
	rt = LOS_W25Q64S_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64S_WriteDisable();//W25Q64禁止写使能
}


void LOS_W25Q64S_BlockErase(uint32_t Block_Address)
{
    uint8_t bytebuf = 0;
    LOS_W25Q64S_WriteEnable();//W25Q64写使能	 
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Block_Erase_64KB, CS_W25Q64_S);
    bytebuf = (Block_Address & 0xFF0000) >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = (Block_Address & 0xFF00) >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = Block_Address & 0xFF;
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    LOS_W25Q64S_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64S_WriteDisable();//W25Q64禁止写使能
}

void LOS_W25Q64S_ChipErase()
{
    LOS_W25Q64S_WriteEnable();//W25Q64写使能	 
    LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_Chip_Erase, CS_W25Q64_S);
    LOS_W25Q64S_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64S_WriteDisable();//W25Q64禁止写使能
}

void LOS_W25Q64S_PageWrite(uint32_t address, uint8_t *data, uint16_t dataSize)
{
    static uint8_t bytebuf;
    uint16_t i  = 0;
    uint16_t chunkSize = 0;
    LOS_W25Q64S_WriteEnable();//W25Q64写使能    
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Page_Program, CS_W25Q64_S);
    bytebuf = (address & 0xFF0000) >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = (address & 0xFF00) >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = address & 0xFF;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);  
    if (dataSize <= 256)
    {
        for (i = 0; i < (dataSize - 1); i++)
        {
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, data[i], CS_W25Q64_S);
        }
        LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, data[i], CS_W25Q64_S);
    }
    else
    {
        for (i = 0; i < 255; i++)
        {
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, data[i], CS_W25Q64_S);
        }
        LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, data[i], CS_W25Q64_S);
        dataSize -= 256;
        data += 256;        
        // 写入剩余数据
        LOS_W25Q64S_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
        address += 256;        
        while (dataSize > 0)
        {
            LOS_W25Q64S_WriteEnable();//W25Q64写使能
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Page_Program, CS_W25Q64_S); 
            bytebuf = (address & 0xFF0000) >> 16;
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
            bytebuf = (address & 0x00FF00) >> 8;
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
            bytebuf = address & 0xFF;
            LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
            chunkSize = (dataSize > 256) ? 256 : dataSize;
            for (i = 0; i < chunkSize - 1; i++)
            {
                LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, data[i], CS_W25Q64_S);
            }
            LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, data[i], CS_W25Q64_S);       
            LOS_W25Q64S_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	         
            dataSize -= chunkSize;
            data += chunkSize;
            address += chunkSize;
        }
    }    
    LOS_W25Q64S_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	
	LOS_W25Q64S_WriteDisable();//W25Q64禁止写使能
}


void LOS_W25Q64S_ReadData(uint32_t address, uint8_t *data, uint16_t dataSize)
{
	uint16_t i;
    uint8_t bytebuf;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_Read_Data, CS_W25Q64_S);
    bytebuf = (address & 0xFF0000) >> 16;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = (address & 0xFF00) >> 8;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    bytebuf = address & 0xFF;
    LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, bytebuf, CS_W25Q64_S);
    for (i = 0; i < dataSize - 1; i++)
    {
        data[i] = LOS_SPI_WriteReadByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64_S);
    }    
    data[i] = LOS_SPI_WriteReadLastByte(LOS_SPI_W25Q64, W25Q64_DUMMY_BYTE, CS_W25Q64_S);
}




